package com.blue.rpc.client;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.blue.rpc.core.message.RpcRequest;
import com.blue.rpc.core.message.RpcResponse;
import com.blue.rpc.util.RpcException;
import com.blue.rpc.util.RpcServerUtil;

public class RpcClientFutureImpl implements RpcClientFuture
{
    private CountDownLatch latch;
    private RpcClientCallback callback;

    private RpcRequest request;
    private RpcResponse response;
    private long start;
    
    public RpcClientFutureImpl(RpcRequest request)
    {
    	this(request, null);
    }
	
	public RpcClientFutureImpl(RpcRequest request, RpcClientCallback callback)
	{
		this.request = request;
		this.callback = callback;
		
		latch = new CountDownLatch(1);
		start = System.currentTimeMillis();
	}

	@Override
	public boolean cancel(boolean mayInterruptIfRunning)
	{
        throw new UnsupportedOperationException();
	}

	@Override
	public boolean isCancelled()
	{
        throw new UnsupportedOperationException();
	}

	@Override
	public boolean isDone()
	{
		return response != null;
	}

	@Override
	public Object get() throws InterruptedException, ExecutionException
	{
		latch.await();
		Exception e = response.getException();
		if (e != null)
		{
			if (e instanceof RuntimeException)
				throw (RuntimeException)e;
			else
				throw new RpcException(e);
		}
		
		return response.getResult();
	}

	@Override
	public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
	{
		boolean success = false;
		success = latch.await(timeout, unit);
		if (!success)
			throw new TimeoutException("等待超时");
		
		Exception e = response.getException();
		if (e != null)
		{
			if (e instanceof RuntimeException)
				throw (RuntimeException)e;
			else
				throw new RpcException(e);
		}
		
		return response.getResult();
	}
	
	public void done(RpcResponse response)
	{
		this.response = response;
		latch.countDown();
		RpcServerUtil.log(request, response, start);
		
		if (callback != null)
		{
			Exception e = response.getException();
			if (e == null)
			{
				callback.success(response.getResult());
			}
			else
			{
				callback.error(e);
			}
		}
	}
	
	public RpcRequest getRequest()
	{
		return request;
	}

	public long getStart()
	{
		return start;
	}
	
}
